package com.yuqiaotech.dbpro.filter.transaction;

import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.log4j.Logger;

import com.yuqiaotech.dbpro.filter.FilterAdapter;
import com.yuqiaotech.dbpro.filter.FilterChain;
import com.yuqiaotech.dbpro.proxy.jdbc.CallableStatementProxy;
import com.yuqiaotech.dbpro.proxy.jdbc.ConnectionProxy;
import com.yuqiaotech.dbpro.proxy.jdbc.ConnectionProxyImpl;
import com.yuqiaotech.dbpro.proxy.jdbc.PreparedStatementProxy;
import com.yuqiaotech.dbpro.proxy.jdbc.ResultSetProxy;
import com.yuqiaotech.dbpro.proxy.jdbc.StatementProxy;

public abstract class TransactionAwareFilterAdapter extends FilterAdapter {
	private static final Logger LOGGER = Logger.getLogger(TransactionAwareFilterAdapter.class);
	
	// 如果当前线程的Connection不是autocommit，则需要放入该变量中
	protected ThreadLocal<TransactionInfoHolder> holderThreadLocal = new ThreadLocal<TransactionInfoHolder>();
	protected AtomicLong transactionAtomic = new AtomicLong();
	
	public ConnectionProxy connection_connect(FilterChain chain, Properties info) throws SQLException {
        connection_connectBefore(chain, info);

        ConnectionProxy connection = super.connection_connect(chain, info);

        connection_connectAfter(connection);

        return connection;
    }

    public void connection_connectBefore(FilterChain chain, Properties info) {

    }

    public void connection_connectAfter(ConnectionProxy connection) {

    }

    @Override
    public StatementProxy connection_createStatement(FilterChain chain, ConnectionProxy connection) throws SQLException {
        StatementProxy statement = super.connection_createStatement(chain, connection);

        statementCreateAfter(statement);

        return statement;
    }

    @Override
    public StatementProxy connection_createStatement(FilterChain chain, ConnectionProxy connection, int resultSetType,
                                                     int resultSetConcurrency) throws SQLException {
        StatementProxy statement = super.connection_createStatement(chain, connection, resultSetType,
                                                                    resultSetConcurrency);

        statementCreateAfter(statement);

        return statement;
    }

    @Override
    public StatementProxy connection_createStatement(FilterChain chain, ConnectionProxy connection, int resultSetType,
                                                     int resultSetConcurrency, int resultSetHoldability)
                                                                                                        throws SQLException {
        StatementProxy statement = super.connection_createStatement(chain, connection, resultSetType,
                                                                    resultSetConcurrency, resultSetHoldability);

        statementCreateAfter(statement);

        return statement;
    }

    @Override
    public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql)
                                                                                                                   throws SQLException {
        CallableStatementProxy statement = super.connection_prepareCall(chain, connection, sql);

        statementPrepareCallAfter(statement);

        return statement;
    }

    @Override
    public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
                                                         int resultSetType, int resultSetConcurrency)
                                                                                                     throws SQLException {
        CallableStatementProxy statement = super.connection_prepareCall(chain, connection, sql, resultSetType,
                                                                        resultSetConcurrency);

        statementPrepareCallAfter(statement);

        return statement;
    }

    @Override
    public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
                                                         int resultSetType, int resultSetConcurrency,
                                                         int resultSetHoldability) throws SQLException {
        CallableStatementProxy statement = super.connection_prepareCall(chain, connection, sql, resultSetType,
                                                                        resultSetConcurrency, resultSetHoldability);

        statementPrepareCallAfter(statement);

        return statement;
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
                                                                                                                        throws SQLException {
        PreparedStatementProxy statement = super.connection_prepareStatement(chain, connection, sql);

        statementPrepareAfter(statement);

        return statement;
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int autoGeneratedKeys) throws SQLException {
        PreparedStatementProxy statement = super.connection_prepareStatement(chain, connection, sql, autoGeneratedKeys);

        statementPrepareAfter(statement);

        return statement;
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int resultSetType, int resultSetConcurrency)
                                                                                                                      throws SQLException {
        PreparedStatementProxy statement = super.connection_prepareStatement(chain, connection, sql, resultSetType,
                                                                             resultSetConcurrency);

        statementPrepareAfter(statement);

        return statement;
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int resultSetType, int resultSetConcurrency,
                                                              int resultSetHoldability) throws SQLException {
        PreparedStatementProxy statement = super.connection_prepareStatement(chain, connection, sql, resultSetType,
                                                                             resultSetConcurrency, resultSetHoldability);

        statementPrepareAfter(statement);

        return statement;
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, int[] columnIndexes) throws SQLException {
        PreparedStatementProxy statement = super.connection_prepareStatement(chain, connection, sql, columnIndexes);

        statementPrepareAfter(statement);

        return statement;
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
                                                              String sql, String[] columnNames) throws SQLException {
        PreparedStatementProxy statement = super.connection_prepareStatement(chain, connection, sql, columnNames);

        statementPrepareAfter(statement);

        return statement;
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
    	StatementInfo info = createStatementInfoBeforeExecute(statement, sql);
        statementExecuteBefore(info);

        try {
            boolean firstResult = super.statement_execute(chain, statement, sql);
            changeStatementInfoAfterExecute(info, autoCommit);
            statementExecuteAfter(info, firstResult);

            return firstResult;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
                                                                                                                    throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
 	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql);    
    	statementExecuteBefore(info);

        try {
            boolean firstResult = super.statement_execute(chain, statement, sql, autoGeneratedKeys);
            changeStatementInfoAfterExecute(info, autoCommit);
            this.statementExecuteAfter(info, firstResult);

            return firstResult;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
                                                                                                                  throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
 	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql);    
    	statementExecuteBefore(info);

        try {
            boolean firstResult = super.statement_execute(chain, statement, sql, columnIndexes);
            changeStatementInfoAfterExecute(info, autoCommit);
            this.statementExecuteAfter(info, firstResult);

            return firstResult;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
                                                                                                                   throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
 	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql);    
    	statementExecuteBefore(info);

        try {
            boolean firstResult = super.statement_execute(chain, statement, sql, columnNames);
            changeStatementInfoAfterExecute(info, autoCommit);
            this.statementExecuteAfter(info, firstResult);

            return firstResult;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public int[] statement_executeBatch(FilterChain chain, StatementProxy statement) throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
 	    StatementInfo info = createStatementInfoBeforeExecute(statement, statement.getBatchSql());  
    	statementExecuteBatchBefore(info);

        try {
            int[] result = super.statement_executeBatch(chain, statement);
            changeStatementInfoAfterExecute(info, autoCommit);
            statementExecuteBatchAfter(info, result);

            return result;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
                                                                                                         throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
 	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql);  
    	statementExecuteQueryBefore(info);

        try {
            ResultSetProxy resultSet = super.statement_executeQuery(chain, statement, sql);

            
            // 这里为什么要判断为null?
            changeStatementInfoAfterExecute(info, autoCommit);
            if (resultSet != null) {
                statementExecuteQueryAfter(info, resultSet);
                resultSetOpenAfter(resultSet);
            }

            return resultSet;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {

        boolean autoCommit = statement.getConnection().getAutoCommit();
 	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql); 
 	    statementExecuteUpdateBefore(info);
        try {
            int updateCount = super.statement_executeUpdate(chain, statement, sql);
            changeStatementInfoAfterExecute(info, autoCommit);
            statementExecuteUpdateAfter(info, updateCount);

            return updateCount;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
                                                                                                                      throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
  	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql); 
    	statementExecuteUpdateBefore(info);

        try {
            int updateCount = super.statement_executeUpdate(chain, statement, sql, autoGeneratedKeys);
            changeStatementInfoAfterExecute(info, autoCommit);
            statementExecuteUpdateAfter(info, updateCount);

            return updateCount;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
                                                                                                                    throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
  	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql); 
    	statementExecuteUpdateBefore(info);

        try {
            int updateCount = super.statement_executeUpdate(chain, statement, sql, columnIndexes);
            changeStatementInfoAfterExecute(info, autoCommit);
            statementExecuteUpdateAfter(info, updateCount);

            return updateCount;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
                                                                                                                     throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
  	    StatementInfo info = createStatementInfoBeforeExecute(statement, sql); 
    	statementExecuteUpdateBefore(info);

        try {
            int updateCount = super.statement_executeUpdate(chain, statement, sql, columnNames);
            changeStatementInfoAfterExecute(info, autoCommit);
            statementExecuteUpdateAfter(info, updateCount);

            return updateCount;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public ResultSetProxy statement_getGeneratedKeys(FilterChain chain, StatementProxy statement) throws SQLException {
        ResultSetProxy resultSet = super.statement_getGeneratedKeys(chain, statement);

        if (resultSet != null) {
            resultSetOpenAfter(resultSet);
        }

        return resultSet;
    }

    @Override
    public ResultSetProxy statement_getResultSet(FilterChain chain, StatementProxy statement) throws SQLException {
        ResultSetProxy resultSet = super.statement_getResultSet(chain, statement);

        if (resultSet != null) {
            resultSetOpenAfter(resultSet);
        }

        return resultSet;
    }

    @Override
    public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
    	StatementInfo info = createStatementInfoBeforeExecute(statement, statement.getSql()); 
        try {
        	statementExecuteBefore(info);
            boolean firstResult = chain.preparedStatement_execute(statement);
            changeStatementInfoAfterExecute(info, autoCommit);
            this.statementExecuteAfter(info, firstResult);

            return firstResult;

        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }

    }

    @Override
    public ResultSetProxy preparedStatement_executeQuery(FilterChain chain, PreparedStatementProxy statement)
                                                                                                             throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
    	StatementInfo info = createStatementInfoBeforeExecute(statement, statement.getSql()); 
        try {
            statementExecuteQueryBefore(info);

            ResultSetProxy resultSet = chain.preparedStatement_executeQuery(statement);

            changeStatementInfoAfterExecute(info, autoCommit);
            if (resultSet != null) {
                statementExecuteQueryAfter(info, resultSet);

                resultSetOpenAfter(resultSet);
            }

            return resultSet;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    @Override
    public int preparedStatement_executeUpdate(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
    	boolean autoCommit = statement.getConnection().getAutoCommit();
    	StatementInfo info = createStatementInfoBeforeExecute(statement, statement.getSql()); 
        try {
            statementExecuteUpdateBefore(info);

            int updateCount = super.preparedStatement_executeUpdate(chain, statement);
            changeStatementInfoAfterExecute(info, autoCommit);
            statementExecuteUpdateAfter(info, updateCount);

            return updateCount;
        } catch (SQLException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (RuntimeException error) {
            statement_executeErrorAfter(info, error);
            throw error;
        } catch (Error error) {
            statement_executeErrorAfter(info, error);
            throw error;
        }
    }

    protected void statementCreateAfter(StatementProxy statement) {

    }

    protected void statementPrepareAfter(PreparedStatementProxy statement) {

    }

    protected void statementPrepareCallAfter(CallableStatementProxy statement) {

    }

    protected void resultSetOpenAfter(ResultSetProxy resultSet) {

    }

    protected void statementExecuteUpdateBefore(StatementInfo statementInfo) {

    }

    protected void statementExecuteUpdateAfter(StatementInfo statementInfo, int updateCount) {

    }

    protected void statementExecuteQueryBefore(StatementInfo statementInfo) {

    }

    protected void statementExecuteQueryAfter(StatementInfo statementInfo, ResultSetProxy resultSet) {

    }

    protected void statementExecuteBefore(StatementInfo statementInfo) {

    }

    protected void statementExecuteAfter(StatementInfo statementInfo, boolean result) {

    }

    protected void statementExecuteBatchBefore(StatementInfo statementInfo) {

    }

    protected void statementExecuteBatchAfter(StatementInfo statementInfo, int[] result) {

    }

    protected void statement_executeErrorAfter(StatementInfo statementInfo, Throwable error) {

    }
    
    
    //-------------------------transaction overides begin--------------------------------------------------
    @Override
    public void connection_setAutoCommit(FilterChain chain, ConnectionProxy connection, boolean autoCommit)
                                                                                                           throws SQLException {
        super.connection_setAutoCommit(chain, connection, autoCommit);
        
        checkTransactionInfo(connection);
        if (autoCommit) {
        	TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
			if (null != transactionInfo) {
				transactionInfo.commit();
				
				// 事务提交后清空当前线程关联的事务
				removeTransactionInfo((ConnectionProxyImpl)connection);
				LOGGER.info("connection_setAutoCommit(autoCommit=true)|removeTransactionInfo");
			}
		}
        
        LOGGER.info("connection_setAutoCommit(autoCommit=" + autoCommit + ")");
    }
    
    @Override
    public void connection_commit(FilterChain chain, ConnectionProxy connection) throws SQLException {
        super.connection_commit(chain, connection);
        
        TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
		if (null != transactionInfo) {
			transactionInfo.commit();
			removeTransactionInfo((ConnectionProxyImpl)connection);
			LOGGER.info("connection_commit|removeTransactionInfo");
		}
		
		LOGGER.info("connection_commit");
    }
    
    @Override
    public void connection_rollback(FilterChain chain, ConnectionProxy connection, Savepoint savepoint)
                                                                                                       throws SQLException {
    	super.connection_rollback(chain, connection, savepoint);
    	TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
        if (null != transactionInfo) {
			transactionInfo.rollback(savepoint);
			LOGGER.info("connection_rollback with savepoint|transactionInfo.rollback");
		}
		LOGGER.info("connection_rollback with savepoint");
    }

    @Override
    public void connection_rollback(FilterChain chain, ConnectionProxy connection)
                                                                                                       throws SQLException {
    	super.connection_rollback(chain, connection);
        TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
		if (null != transactionInfo) {
			transactionInfo.rollback();
			LOGGER.info("connection_rollback|transactionInfo.rollback");
		}
		
		LOGGER.info("connection_rollback");
    }
    
    @Override
    public Savepoint connection_setSavepoint(FilterChain chain, ConnectionProxy connection) throws SQLException {
    	Savepoint savepoint = super.connection_setSavepoint(chain, connection);
    	TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
 		if (null != transactionInfo) {
 			transactionInfo.addSavepoint(savepoint);
 			LOGGER.info("connection_setSavepoint|transactionInfo.addSavepoint");
 		}
    	
 		LOGGER.info("connection_setSavepoint");
    	return savepoint;
    }

    @Override
    public Savepoint connection_setSavepoint(FilterChain chain, ConnectionProxy connection, String name)
                                                                                                        throws SQLException {
    	Savepoint savepoint = super.connection_setSavepoint(chain, connection, name);
    	TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
 		if (null != transactionInfo) {
 			transactionInfo.addSavepoint(savepoint);
 			LOGGER.info("connection_setSavepoint with name|transactionInfo.addSavepoint");
 		}
    	
 		LOGGER.info("connection_setSavepoint with name");
    	return savepoint;
    }
    
    @Override
    public void connection_releaseSavepoint(FilterChain chain, ConnectionProxy connection, Savepoint savepoint)
                                                                                                               throws SQLException {
        super.connection_releaseSavepoint(chain, connection, savepoint);
        
        TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
 		if (null != transactionInfo) {
 			transactionInfo.removeSavepoint(savepoint);
 			LOGGER.info("connection_releaseSavepoint|transactionInfo.removeSavepoint");
 		}
 		
        LOGGER.info("connection_releaseSavepoint");
        
    }
    
    
    //-------------------------transaction overides end--------------------------------------------------
    /**
     * 在创建statement之前需要检查是否是autocommit
     * 
     * @param connection
     */
    private void checkTransactionInfo(ConnectionProxy connection) {
    	try {
    		// 如果不是autocommit，需要创建一个TransactionInfo对象与ConnectionProxy关联
    		// 如果是autocommit，那么需要提交当前的事务对象并删除关联的transactionInfo对象
    		TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)connection);
			if (!connection.getRawConnection().getAutoCommit()) {
				if (null == transactionInfo) {
					transactionInfo = new TransactionInfo();
					transactionInfo.setCreateTime(System.currentTimeMillis());
					transactionInfo.setTransactionId(transactionAtomic.getAndIncrement());
					addTransactionInfo(transactionInfo, (ConnectionProxyImpl)connection);
				}
			} else {
				// 这else分支应该很少出现
				if (null != transactionInfo) {
					// 大多数情况下transactionInfo中statmentInfo都是为空的
					transactionInfo.commit();
					TransactionInfoHolder holder = holderThreadLocal.get();
					if (null != holder) {
						holder.transactionInfoMap.remove(connection.getId());
						if (holder.transactionInfoMap.isEmpty()) {
							holderThreadLocal.remove();
						}
					}
					LOGGER.info("checkTransactionInfo|transactionInfo.commit");
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
    }
    
    // 在statement执行前会调用该方法
    private StatementInfo createStatementInfoBeforeExecute(StatementProxy statement, String sql) {
    	checkTransactionInfo(statement.getConnectionProxy());
    	
    	TransactionInfo transactionInfo = getCurrentTransactionInfo((ConnectionProxyImpl)statement.getConnectionProxy());
    	StatementInfo info = new StatementInfo();
    	info.setSql(sql);
    	info.status = StatementInfo.BEGIN;
    	if (null != transactionInfo) {
    		info.setTransactionId(transactionInfo.getTransactionId());
    		transactionInfo.addStatementInfo(info);
    	}
    	int paramsSize = statement.getParametersSize();
    	Object[] params = new Object[paramsSize];
    	for (int i = 0; i < paramsSize; i++) {
    		params[i] = statement.getParameter(i).getValue();
    	}
    	info.setParams(params);
    	
    	return info;
    }
    
    // 在statement执行后会调用该方法修改status状态和时间
    private void changeStatementInfoAfterExecute(StatementInfo info, boolean autoCommit) {
    	long now = System.currentTimeMillis();
    	if (autoCommit) {
    		info.status = StatementInfo.COMMITTED;
    		info.setCommitTime(now);
    	} else {
    		info.status = StatementInfo.UNCOMMITTED;
    	}
    	info.setAfterExecuteTime(now);
    }
    
    /**
     * 
     * @author Administrator
     *
     */
    private class TransactionInfoHolder {
    	Map<Long, TransactionInfo> transactionInfoMap;
    	public TransactionInfoHolder() {
    		transactionInfoMap = new HashMap<Long, TransactionInfo>();
    	}
    }
    
    /**
     * 当前线程正处于的事务，一个线程可以开启多个事务
     * @return
     */
    public TransactionInfo getCurrentTransactionInfo(ConnectionProxyImpl connectionProxy) {
    	TransactionInfo info = null;
    	TransactionInfoHolder holder = holderThreadLocal.get();
    	if (null != holder) {
    		info = holder.transactionInfoMap.get(connectionProxy.getId());
    	}
    	return info;
    }
    
    public void addTransactionInfo(TransactionInfo info, ConnectionProxyImpl connectionProxy) {
    	if (null == info) return;
    	
    	long connectionId = connectionProxy.getId();
    	TransactionInfoHolder holder = holderThreadLocal.get();
    	if (null == holder) {
    		holder = new TransactionInfoHolder();
    		holderThreadLocal.set(holder);
    	}
    	if (holder.transactionInfoMap.containsKey(connectionId)) {
    		LOGGER.warn("TransactionInfo is already exists and will be overwrite, connectionId is " + connectionId);
    	}
    	
    	holder.transactionInfoMap.put(connectionId, info);
    }
    
    public void removeTransactionInfo(ConnectionProxyImpl connectionProxy) {
    	long connectionId = connectionProxy.getId();
    	TransactionInfoHolder holder = holderThreadLocal.get();
    	if (null == holder) {
    		LOGGER.warn("Current thread has no transactionInfoHolder.");
    		return;
    	}
    	
    	if (!holder.transactionInfoMap.containsKey(connectionId)) {
    		LOGGER.warn("Current thread's holder has no transactionInfo.");
    		return;
    	}
    	
    	holder.transactionInfoMap.remove(connectionId);
    	if (holder.transactionInfoMap.isEmpty()) {
    		holderThreadLocal.remove();
    	}
    	
    }

}
